/*
 * auimenubar.cpp
 *
 *  Created on: 2012-7-27
 *      Author: Yangde
 */


#include "wx/dcclient.h"
#include "wx/dcbuffer.h"

#include "auiutils.h"
#include "framemanager.h"
#include "auimenubar.h"
#include "auimenu.h"

IMPLEMENT_CLASS(auiMenuBar, wxControl)

BEGIN_EVENT_TABLE(auiMenuBar, wxControl)
    EVT_SIZE(auiMenuBar::OnSize)
    EVT_IDLE(auiMenuBar::OnIdle)
    EVT_ERASE_BACKGROUND(auiMenuBar::OnEraseBackground)
    EVT_PAINT(auiMenuBar::OnPaint)
    EVT_LEFT_DOWN(auiMenuBar::OnLeftDown)
    EVT_LEFT_DCLICK(auiMenuBar::OnLeftDown)
    EVT_LEFT_UP(auiMenuBar::OnLeftUp)
    EVT_RIGHT_DOWN(auiMenuBar::OnRightDown)
    EVT_RIGHT_DCLICK(auiMenuBar::OnRightDown)
    EVT_RIGHT_UP(auiMenuBar::OnRightUp)
    EVT_MIDDLE_DOWN(auiMenuBar::OnMiddleDown)
    EVT_MIDDLE_DCLICK(auiMenuBar::OnMiddleDown)
    EVT_MIDDLE_UP(auiMenuBar::OnMiddleUp)
    EVT_MOTION(auiMenuBar::OnMotion)
    EVT_LEAVE_WINDOW(auiMenuBar::OnLeaveWindow)
    EVT_MOUSE_CAPTURE_LOST(auiMenuBar::OnCaptureLost)
    EVT_SET_CURSOR(auiMenuBar::OnSetCursor)
    EVT_KILL_FOCUS(auiMenuBar::OnKillFocus)
    EVT_KEY_DOWN(auiMenuBar::OnKeyDown)
END_EVENT_TABLE()


auiMenuBar::auiMenuBar(wxWindow* parent,
                           wxWindowID id,
                           const wxPoint& position,
                           const wxSize& size,
                           long style)
                            : wxControl(parent,
                                        id,
                                        position,
                                        size,
                                        style | wxBORDER_NONE)
{
	r_padding = l_padding = 9;
	t_padding = b_padding = 3;

	r_margins = 2;l_margins = 0;
	t_margins = 1; b_margins = 5;
	active_menu = -1;
	last_show_menu = -1;
	reset_flag = false;
	is_show_menu = false;
	SetFont(*wxNORMAL_FONT);
	SetBackgroundStyle(wxBG_STYLE_CUSTOM);

	m_frame = (wxFrame*)parent;

}

bool auiMenuBar::Append( auiMenu *menu, const wxString &title )
{
	int last_pos = menubar_menus.GetCount();
	menubar_menus.Insert(menu,last_pos);
	menu->setTitle(title);
	menu->SetMenuType(auiMENU_MAIN);
	menu->SetMenuBar(this);
	return true;
}

bool auiMenuBar::Realize()
{
	wxClientDC dc(this);
	if (!dc.IsOk())
		return false;

	int x,y;
	dc.SetFont(menubar_font);
	dc.GetTextExtent(wxT("ABCDHgj"),&x,&y);
	int height = y+t_margins+b_margins+t_padding+b_padding;
	int width = l_margins;

	for (int i=0;i<menubar_menus.GetCount();i++)
	{
		dc.GetTextExtent(menubar_menus[i].GetTitle(),&x,&y);

		int w = x+l_padding+r_padding;
		menubar_menus[i].SetWidth(w);
		width += w;

	}
	width += r_margins;

	menubar_sizer = new wxBoxSizer(wxHORIZONTAL);
	menubar_sizer->Add(width,height);
	wxSize size = menubar_sizer->GetMinSize();
	m_minWidth = size.x;
	m_minHeight = size.y;

	wxSize curSize = GetClientSize();
	wxSize new_size = GetMinSize();
	if (new_size != curSize) {
		SetClientSize(new_size);
	} else {
		menubar_sizer->SetDimension(0, 0, curSize.x, curSize.y);
	}

	Refresh(false);
	return true;
}

void auiMenuBar::DoSetSize(int x,
                             int y,
                             int width,
                             int height,
                             int sizeFlags)
{
    wxSize parent_size = GetParent()->GetClientSize();
    if (x + width > parent_size.x)
        width = wxMax(0, parent_size.x - x);
    if (y + height > parent_size.y)
        height = wxMax(0, parent_size.y - y);

    wxWindow::DoSetSize(x, y, width, height, sizeFlags);
}

bool auiMenuBar::SetFont(const wxFont& font)
{
    bool res = wxWindow::SetFont(font);
    menubar_font = font;
    menubar_font_u = font;
    menubar_font_u.SetUnderlined(true);
    return res;
}


void auiMenuBar::OnPaint(wxPaintEvent& evt)
{
	wxAutoBufferedPaintDC dc(this);
	wxRect cli_rect(wxPoint(0,0), GetClientSize());
	int row_type = 0;
	// find aui manager
	wxAuiManager* manager = wxAuiManager::GetManager(this);
	if (manager)
	{
		row_type = manager->GetPane(this).row_type;
	}

	wxAuiUtils::GetInstance()->DrawToolBar(dc,cli_rect,row_type);
	dc.SetFont(menubar_font);
	int x,y;
	dc.GetTextExtent(wxT("ABCDHgj"),&x,&y);
	font_height = y;

	int ty=(cli_rect.height-font_height)/2;
	int tx = l_margins;

	tx += l_padding;

	for (int i=0;i<menubar_menus.GetCount();i++)
	{
		auiMenu& m = menubar_menus[i];
		if(i == active_menu)
		{
//			dc.SetPen(wxPen(wxAuiUtils::GetInstance()->m_highlightColour));
//			dc.SetBrush(wxBrush(wxAuiUtils::GetInstance()->m_highlightColour));
//			dc.DrawRectangle(tx-l_padding,ty-t_padding,m.GetWidth(),font_height+t_padding+b_padding);
            wxRect rect = wxRect(tx-l_padding,ty-t_padding,m.GetWidth(),font_height+t_padding+b_padding);
			wxAuiUtils::GetInstance()->DrawMenuHighlight(dc,rect);

			dc.SetTextForeground(wxAuiUtils::GetInstance()->m_highlightTextColour);
		}
		else
		{
			dc.SetTextForeground(wxColor(0,0,0));
		}

//		dc.DrawText(m.GetTitle(),tx,ty);
		wxAuiUtils::GetInstance()->DrawMenuText(m.GetTitle(),dc,tx,ty,m.sys_char_i);

		tx+=(m.GetWidth());
	}


}

void auiMenuBar::ReSet()
{
	active_menu = -1;
	is_show_menu = false;
	last_show_menu = -1;
	reset_flag = true;
	Refresh(false);
	if(HasCapture())
	{
		ReleaseMouse();
	}
}

wxPoint auiMenuBar::GetPopupPoint(int index)
{
	wxPoint pt;
	pt.y = (GetClientSize().GetHeight()-font_height)/2;
	pt.y += (font_height+b_padding);
	pt.x = l_margins;

	for (int i=0;i<index&&i<menubar_menus.GetCount();i++)
	{
		pt.x += menubar_menus[i].GetWidth();
	}

	return pt;
}

void auiMenuBar::ClickItem(int itemno)
{

	if (itemno != -1) {
		active_menu = itemno;

		if (!is_show_menu) {
			wxPoint pop_pos = ClientToScreen(GetPopupPoint(active_menu));
			menubar_menus[active_menu].m_popupMenu->MainMenuAdjustPosition(pop_pos,GetItemHeight());
			menubar_menus[active_menu].Popup(this);
			last_show_menu = active_menu;
			is_show_menu = true;
		}
		else
		{
			menubar_menus[active_menu].Dismiss();
			last_show_menu = -1;
			is_show_menu = false;
		}
	} else {
		/*on the margins*/
		active_menu = -1;
		last_show_menu = -1;
		is_show_menu = false;
	}

	Refresh(false);
}

void auiMenuBar::ProcessLeftDown(const wxPoint& pt)
{
	int curent_menu = FindMenuByPosition(pt);
	ClickItem(curent_menu);
}


void auiMenuBar::ProcessMouseMove(const wxPoint& pt)
 {
	static wxPoint s_ptLast;
	if (pt == s_ptLast) {
		return;
	}
	s_ptLast = pt;

	int index = FindMenuByPosition(pt);

	if (is_show_menu) {
		if (index==-1 || index == active_menu) {
			return;
		} else {
			menubar_menus[last_show_menu].Dismiss();
			active_menu = index;

			wxPoint pop_pos = ClientToScreen(GetPopupPoint(active_menu));
			menubar_menus[active_menu].m_popupMenu->MainMenuAdjustPosition(pop_pos,GetItemHeight());
			menubar_menus[active_menu].Popup(this);

			last_show_menu = active_menu;
		}
	} else {
		active_menu = index;
	}

	Refresh(false);
}
void auiMenuBar::OnMotion(wxMouseEvent& evt)
{

	ProcessMouseMove(evt.GetPosition());

}

void auiMenuBar::OnLeftDown(wxMouseEvent& evt)
 {

		wxPoint pt = evt.GetPosition();
		ProcessLeftDown(pt);
}

int auiMenuBar::FindMenuByPosition(const wxPoint& pt)
{
	int ty=(GetClientSize().y-font_height)/2;

	if(pt.y<=ty-t_padding||pt.y>=ty+font_height+b_padding)
		return -1;

	int start = l_margins;

	for (int i=0;i<menubar_menus.GetCount();i++)
	{
		int w = menubar_menus[i].GetWidth();
		if(pt.x>=start&&pt.x<(start+w))
			return  i;
		start += w;
	}

	return -1;
}


void auiMenuBar::OnLeaveWindow(wxMouseEvent& evt)
{

    if(!is_show_menu)
    {
    	active_menu = -1;
    }

    Refresh(false);
}



void auiMenuBar::GiveAwayFocus()
{}



void auiMenuBar::RefreshItem(size_t pos)
{
    wxCHECK_RET( pos != (size_t)-1,
                 wxT("invalid item in wxMenuBar::RefreshItem") );


    RefreshRect(GetItemRect(pos));
}

int auiMenuBar::GetItemHeight() const
{
	return t_padding+font_height+b_padding;
}

wxRect auiMenuBar::GetItemRect(size_t pos) const
{
    wxRect rect;
    rect.x =
    rect.y = 0;
    rect.height = GetClientSize().y;

    for ( size_t n = 0; n < pos; n++ )
    {
        rect.x += GetItemWidth(n);
    }

    rect.width = GetItemWidth(pos);

    return rect;
}

int auiMenuBar::GetItemWidth(size_t pos) const
{
	return menubar_menus[pos].GetWidth();
}


void auiMenuBar::OnKillFocus(wxFocusEvent& event)
{}

void auiMenuBar::OnKeyDown(wxKeyEvent& event)
 {
	int keycode = event.GetKeyCode();
	if (is_show_menu && (-1 != last_show_menu)) {

		if(menubar_menus[last_show_menu].ProcessKeyDown(keycode))
			return;

		if (keycode == WXK_RIGHT) {

			menubar_menus[last_show_menu].Dismiss();
			is_show_menu = false;

			int nest = last_show_menu + 1;
			if (nest >= menubar_menus.GetCount())
				nest = 0;
			active_menu = nest;
			wxPoint pop_pos = ClientToScreen(GetPopupPoint(active_menu));
			menubar_menus[active_menu].m_popupMenu->MainMenuAdjustPosition(pop_pos,GetItemHeight());
			menubar_menus[active_menu].Popup(this,true);
			last_show_menu = active_menu;
			is_show_menu = true;

		}else if (keycode == WXK_LEFT) {

			menubar_menus[last_show_menu].Dismiss();
			is_show_menu = false;

			int nest= last_show_menu;
			if (nest==0)
				nest =  menubar_menus.GetCount();
            nest --;

			active_menu = nest;
			wxPoint pop_pos = ClientToScreen(GetPopupPoint(active_menu));
			menubar_menus[active_menu].m_popupMenu->MainMenuAdjustPosition(pop_pos,GetItemHeight());
			menubar_menus[active_menu].Popup(this,true);
			last_show_menu = active_menu;
			is_show_menu = true;
		}

		Refresh(false);
	}

}


#include <windows.h>
void auiMenuBar::ProcessSysMsg(WXMSG *msg)
{
	unsigned int msgid = msg->message;
	unsigned int keycode = msg->wParam;
	if(msgid==260/*WM_SYSKEYDOWN*/)
	{
		if(keycode==18/*VK_MENU*/)
		{
			if (last_show_menu != -1) {
				menubar_menus[last_show_menu].Dismiss();
			}
			ReSet();
			return;
		}
		for(int i=0;i<menubar_menus.GetCount();i++)
		{
			if(keycode == menubar_menus[i].GetSysKey())
			{
				if(i!=last_show_menu)
				{
					if(last_show_menu!=-1)
					{
						menubar_menus[last_show_menu].Dismiss();
						is_show_menu = false;
					}
					active_menu = i;
					wxPoint pop_pos = ClientToScreen(GetPopupPoint(active_menu));
					menubar_menus[active_menu].m_popupMenu->MainMenuAdjustPosition(pop_pos,GetItemHeight());
					menubar_menus[active_menu].Popup(this,true);
					last_show_menu = active_menu;
					is_show_menu = true;

				}

				Refresh(false);
			}
		}
	}

	return;
}



